﻿Imports System.Net.Sockets
''' <summary>
''' Holds either a Server or A Client Class for a Game in Order to recieve Data or Send it.
''' </summary>
''' <remarks></remarks>
Public Class GameConnection
    Dim Client As ClientClassGame
    Dim Server As ServerClassGame
    ''' <summary>
    ''' Starts a new Connection
    ''' </summary>
    ''' <param name="Hosten"></param>
    ''' <param name="IP"></param>
    ''' <remarks></remarks>
    Public Function IniConnection(ByVal Hosten As Boolean, Optional ByVal IP As System.Net.IPAddress = Nothing, Optional ByVal Local As Boolean = False) As Boolean
        If Hosten Then
            Server = New ServerClassGame()
            Server.LaunchServer(Hauptmenue.GamePort, Local)
            Return True
        Else
            If IP Is Nothing Then
                Client = New ClientClassGame

                Return Client.Connect(Hauptmenue.GamePort)
            Else
                Client = New ClientClassGame
                Return Client.Connect("", IP, Hauptmenue.GamePort)
            End If
        End If
        Return False
    End Function
    ''' <summary>
    ''' Send Data to other Player
    ''' </summary>
    ''' <param name="Data"></param>
    ''' <remarks></remarks>
    Public Sub SendData(ByVal Data As NetworkPaket)
        If Server IsNot Nothing Then
            Server.AddServerPaket(Data)
        ElseIf Client IsNot Nothing Then
            Client.SendData(Data)
        End If
    End Sub
    ''' <summary>
    ''' Send Data to other Player
    ''' </summary>
    ''' <param name="Data"></param>
    ''' <remarks></remarks>
    Public Sub SendData(ByVal Data As NetworkPaket, ByVal PlayerID As Integer)
        If Server IsNot Nothing Then
            Server.AddServerPaket(Data, PlayerID)
        End If
    End Sub
    ''' <summary>
    ''' Are we connected with somebody?
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Connected() As Boolean
        If Server IsNot Nothing Then
            Return Server.NetzConnected
        ElseIf Client IsNot Nothing Then
            Return Client.NetzConnected
        Else
            Return False
        End If
    End Function
    ''' <summary>
    ''' Are we the Host this Game?
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Hosten() As Boolean
        If Server IsNot Nothing Then
            Return True
        Else
            Return False
        End If
    End Function
    ''' <summary>
    ''' We won't to close this connection
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Close(ByVal WithClosed As Boolean)
        Dim Hosten As Boolean = Hosten
        If Server IsNot Nothing Then
            Server.Close()
        End If
        If Client IsNot Nothing Then
            Client.Close()
        End If
        If WithClosed Then
            Closed()
        End If
    End Sub
    Public Sub Closed()
        Select Case Hauptmenue.Formmodus
            Case Hauptmenue.Formmodi.Spiel
                Hauptmenue.Ini(Hauptmenue.Formmodi.SiegMenue)
            Case Hauptmenue.Formmodi.KartenauswahlMP
                If Not Hosten() Then 'Not a Host go back to Map-Selection.
                    Hauptmenue.Ini(Hauptmenue.Formmodi.KartenauswahlMP)
                End If
            Case Else
                Hauptmenue.Ini(Hauptmenue.Formmodi.Hauptmenue)
        End Select
    End Sub
    Public Function IsGameReady() As Boolean
        If Server IsNot Nothing Then
            If Not Server.IsGameReady Then
                Return False
            End If
        End If
        If Client IsNot Nothing Then
            If Not Client.IsGameReady Then
                Return False
            End If
        End If
        Return True
    End Function
    ''' <summary>
    ''' Updates this Connection
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Update()
        If Server IsNot Nothing Then
            'Send first Update if needed
            Server.SendFirstUpdate()
            'Send Server Pakets
            Server.SendPakets()
            'Checks for Ready Signal
            Server.SendReady()
        End If
    End Sub
    Public Sub IsReady(ByVal Ready As Net_Orders)
        If Server IsNot Nothing Then
            Server.IsReady(Ready)
        End If
    End Sub

    Public Shared Function RecievePaket(ByRef TcpClient As TcpClient) As NetworkPaket
        Dim Data As New List(Of Byte)
        Dim CurrentPos As Integer
        Dim StartByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders.Start0000000000000000_.ToString)
        Dim EndByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders._End0000000000000000.ToString)
        If TcpClient.Available > 0 And Not TcpClient.NoDelay Then
            Dim ReadOut As Integer = CInt(TcpClient.Available)
            If ReadOut > TcpClient.ReceiveBufferSize Then
                ReadOut = TcpClient.ReceiveBufferSize
            End If
            Dim bytes(ReadOut - 1) As Byte 'Output
            Dim networkStream As NetworkStream = TcpClient.GetStream()
            If networkStream.CanRead Then
                Try
                    networkStream.Read(bytes, 0, ReadOut)
                    Data.AddRange(bytes)
                    bytes = Data.ToArray
                    Dim StartCorrect As Boolean = False
                    Dim EndCorrect As Boolean = False
                    While CurrentPos < bytes.Length
                        If Not StartCorrect Then
                            For I = 0 To StartByte.Length - 1
                                If I < bytes.Length Then
                                    If bytes(I) <> StartByte(I) Then
                                        StartCorrect = False
                                        Exit For
                                    ElseIf I = StartByte.Length - 1 Then
                                        StartCorrect = True
                                    End If
                                End If
                            Next
                        End If
                        If Not EndCorrect Then
                            For I = 0 To EndByte.Length - 1
                                If CurrentPos - I >= 0 Then
                                    If bytes(CurrentPos - I) <> EndByte(EndByte.Length - I - 1) Then
                                        EndCorrect = False
                                        Exit For
                                    ElseIf I = EndByte.Length - 1 Then
                                        EndCorrect = True
                                    End If
                                End If
                            Next
                        End If
                        If StartCorrect And EndCorrect Then
                            EndCorrect = False
                            StartCorrect = False
                            Dim B(CurrentPos - StartByte.Length - EndByte.Length) As Byte
                            Array.ConstrainedCopy(bytes, StartByte.Length, B, 0, B.Length)
                            Data.RemoveRange(0, CurrentPos + 1)
                            bytes = Data.ToArray
                            CurrentPos = 0
                            Return New NetworkPaket(B)
                        End If
                        CurrentPos += 1
                    End While
                Catch
                End Try
            End If
        End If
        Return Nothing
    End Function
    Public Function GetServerClients() As List(Of Integer)
        If Server IsNot Nothing Then
            Return Server.GetServerClients()
        End If
        Return Nothing
    End Function
End Class

''' <summary>
''' This Class manages the Client Side of a Game.
''' </summary>
''' <remarks></remarks>
''' 
Public Class ClientClassGame

    Public WaitRecieving As Boolean = False
    ''' <summary>
    ''' Das letzte Paket was versucht wurde zu senden.
    ''' </summary>
    ''' <remarks></remarks>
    Dim LastPaket As NetworkPaket
    ''' <summary>
    ''' Paket wurde vom Server empfangen?
    ''' </summary>
    ''' <remarks></remarks>
    Dim PaketRecevied As Boolean = False
    ''' <summary>
    ''' Paket Counter Client zum Server
    ''' </summary>
    ''' <remarks></remarks>
    Dim ClientDataCounter As UInt64
    ''' <summary>
    ''' Paket Counter Server zum Client  
    ''' </summary>
    ''' <remarks></remarks>
    Dim ServerDataCounter As UInt64
    ''' <summary>
    ''' Client Listener
    ''' </summary>
    ''' <remarks></remarks>
    Dim tcpClient As System.Net.Sockets.TcpClient
    ''' <summary>
    ''' Listening Thread
    ''' </summary>
    ''' <remarks></remarks>
    Dim ListenThread As Threading.Thread
    ''' <summary>
    ''' Closing connection
    ''' </summary>
    ''' <remarks></remarks>
    Dim CloseConnection As Boolean = False
    ''' <summary>
    ''' Is this Game ready to Start?
    ''' </summary>
    ''' <remarks></remarks>
    Dim Ready As Boolean = False
    ''' <summary>
    ''' Backbuffer for our read in.
    ''' </summary>
    ''' <remarks></remarks>
    Dim Data As New List(Of Byte)
    ''' <summary>
    ''' The Current Position of our Reader.
    ''' </summary>
    ''' <remarks></remarks>
    Dim CurrentPos As Integer
    ''' <summary>
    ''' Did we have a connection
    ''' </summary>
    ''' <remarks></remarks>
    Dim HasConnected As Boolean = False
    ''' <summary>
    ''' Sending or Listening to Server  Pakets.
    ''' </summary>
    ''' <remarks></remarks>
    Dim SendListenMutex As New Mutex
    ''' <summary>
    ''' You need to enter the new IP.
    ''' </summary>
    ''' <remarks></remarks>
    Public Function Connect(ByVal Port As Integer) As Boolean
        If MessageBox.ShowEnterIP = MsgBoxResult.Yes Then
            Dim IP As System.Net.IPAddress = Nothing
            If System.Net.IPAddress.TryParse(MessageBox.Output(0), IP) Then
                If Connect(MessageBox.Output(0), IP, Port) Then Return True
            Else
                Try
                    Dim IPEnter As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(MessageBox.Output(0))
                    For I = 0 To IPEnter.AddressList.Length - 1
                        If IPEnter.AddressList(I).IsIPv6LinkLocal = False Then
                            If IPEnter.AddressList(I).IsIPv6Multicast = False Then
                                If IPEnter.AddressList(I).IsIPv6SiteLocal = False Then
                                    IP = IPEnter.AddressList(I)
                                    Connect(MessageBox.Output(0), IP, Port)
                                    Return True
                                    Exit For
                                End If
                            End If
                        End If
                        If I = IPEnter.AddressList.Length - 1 Then
                            Konsole.Write("Host IP not found.")
                            Close()
                        End If
                    Next
                Catch
                    Konsole.Write("Host IP not found.")
                    Close()
                End Try
            End If
        End If
        Return False
    End Function
    ''' <summary>
    ''' Connects with the IP and the Input Port.
    ''' </summary>
    ''' <param name="IP"></param>
    ''' <param name="Port"></param>
    ''' <remarks></remarks>
    Public Function Connect(ByVal IPStr As String, ByVal IP As System.Net.IPAddress, ByVal Port As Integer) As Boolean
        If IP Is Nothing And IPStr = "" Then
            Return Connect(Port)
        Else
            If IPStr <> "" Then
                Try
                    tcpClient = New System.Net.Sockets.TcpClient()
                    tcpClient.Connect(IPStr, Port)
                    tcpClient.ReceiveBufferSize = NetworkPaket.MaxRecieveBuffer

                    ListenThread = New Threading.Thread(AddressOf RecieveData)
                    ListenThread.Name = "Client Game Listening"
                    ListenThread.Start()
                    Return True
                Catch ex As Exception
                    Konsole.Write("Host Error! " + ex.Message)
                End Try
            End If
            Try
                tcpClient = New System.Net.Sockets.TcpClient(IP.AddressFamily) 'Create New Client
                tcpClient.Connect(IP, Port)
                tcpClient.ReceiveBufferSize = NetworkPaket.MaxRecieveBuffer
                ListenThread = New Threading.Thread(AddressOf RecieveData)
                ListenThread.Name = "Client Game Listening"
                ListenThread.Start()
                Return True
            Catch
                Try
                    If IP.AddressFamily = AddressFamily.InterNetworkV6 Then
                        IP = ConvertToNetworkIP(IP)
                    Else
                        IP = ConvertToInternetIP(IP)
                    End If
                    tcpClient = New System.Net.Sockets.TcpClient(IP.AddressFamily) 'Create New Client
                    tcpClient.Connect(IP, Port)
                    tcpClient.ReceiveBufferSize = NetworkPaket.MaxRecieveBuffer
                    ListenThread = New Threading.Thread(AddressOf RecieveData)
                    ListenThread.Name = "Client Game Listening"
                    ListenThread.Start()
                    Return True
                Catch ex As Exception
                    Konsole.Write("Host not found! " + ex.Message)
                End Try
            End Try
        End If
        Return False
    End Function
    ''' <summary>
    ''' Closes this Client Session.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Close()
        CloseConnection = True
        If ListenThread IsNot Nothing Then
            ListenThread.Abort()
        End If
        If tcpClient IsNot Nothing Then
            If tcpClient.Connected Then
                'Delete us from Host List
                If TypeOf Objektverwalter.Menue Is ObjektKartenauswahlMenue Then
                    Dim M As ObjektKartenauswahlMenue = Objektverwalter.Menue
                    For I = 0 To M.KIStufen.Length - 1
                        If M.KIStufen(I) = ObjektSpieler.KIStufen.Mensch Then
                            Hauptmenue.NetzBefehlKartenauswahlSendenKI(I, ObjektSpieler.KIStufen.Offen.ToString, "Anonym")
                            Hauptmenue.NetzBefehlKartenauswahlSendenKO(I, "Nothing", 0)
                            Hauptmenue.NetzBefehlKartenauswahlSendenKO(I, "Nothing", 1)
                        End If
                    Next
                End If
                SendData(New NetworkPaket(Net_Orders.Close_Connection.ToString))
                tcpClient.Close()
            End If
        End If
    End Sub

#Region "Client to Server"
    ''' <summary>
    ''' Send Data to Host
    ''' </summary>
    ''' <param name="Input"></param>
    ''' <remarks></remarks>
    Public Sub SendData(ByVal Input As NetworkPaket)
        If tcpClient IsNot Nothing Then
            If NetzConnected() Then
                PaketRecevied = False
                'Letzte Paket wurde vom Server Empfangen alles ist gut
                LastPaket = Input
                SendListenMutex.Lock()
                If SendDatatoServer(Input) Then
                    WaitRecieving = True
                    SendListenMutex.Unlock()
                    Dim TimeoutCounter As Long = Now.Ticks
                    'We don't need to send an answer or wait for it if it's a Message Recieved Message
                    While Not DataRecieved(TimeoutCounter)
                        Threading.Thread.Sleep(ThreadSleepTime)
                    End While
                    WaitRecieving = False
                End If
            End If
        End If
    End Sub
    ''' <summary>
    ''' Wir senden Daten zum Server.
    ''' </summary>
    ''' <param name="Input"></param>
    ''' <remarks></remarks>
    Private Function SendDatatoServer(ByVal Input As NetworkPaket) As Boolean

        Dim P As New NetworkPaket()
        P.Write(ClientDataCounter.ToString + "|")
        P.Write(Input.ReadAll)
        Dim Data As Byte() = NetworkPaket.GenerateByteStream(P.ReadAll)
        Try
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            While Not networkStream.CanWrite
                Threading.Thread.Sleep(ThreadSleepTime)
            End While
            Dim DataSended As Boolean = False
            While Not DataSended And tcpClient.Client.Connected
                networkStream.Write(Data, 0, Data.Length) 'Sending Data
                DataSended = True
            End While
            ClientDataCounter += 1
        Catch e As Exception
            Konsole.Write("Sending Error: " + e.ToString)
            Return False
        End Try
        Return True
    End Function
    ''' <summary>
    ''' Did all Clients recieve our message?
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function DataRecieved(ByRef LastRun As Long) As Boolean
        SendListenMutex.Lock()
        If PaketRecevied = False Then
            If Now.Ticks - LastRun > Hauptmenue.ServerTimeOut Then
                If ClientDataCounter > 0 Then
                    ClientDataCounter -= 1
                End If
                SendDatatoServer(LastPaket)
                LastRun = Now.Ticks
            End If
            SendListenMutex.Unlock()
            Return False
        End If
        SendListenMutex.Unlock()
        Return True
    End Function
#End Region

#Region "Server to Client"
    ''' <summary>
    ''' Recieve Data
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub RecieveData()
        Dim StartByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders.Start0000000000000000_.ToString)
        Dim EndByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders._End0000000000000000.ToString)
        While Not CloseConnection And (Not HasConnected Or NetzConnected())
            If Not HasConnected Then
                If NetzConnected() Then
                    HasConnected = True
                End If
            End If
            If tcpClient IsNot Nothing Then
                SendListenMutex.Lock()
                Dim CurrentData As NetworkPaket = GameConnection.RecievePaket(tcpClient)
                If CurrentData IsNot Nothing Then
                    If CheckPaket(CurrentData.ReadString) Then
                        Select Case CurrentData.ReadString.Split("|")(1)
                            Case Net_Orders.Player_Ready.ToString
                                Ready = True
                            Case Net_Orders.Player_Not_Ready.ToString
                                Ready = False
                            Case Net_Orders.Close_Connection.ToString
                                Close() 'We get closed
                                Exit Sub
                            Case Else
                                'Nur einmal dürfen wir einen Befehl asuführen Clients don't own an ID
                                Hauptmenue.NetzBefehlRecieved(CurrentData, 0)
                        End Select
                    End If
                    Dim S As String = CurrentData.ReadString()
                End If
                SendListenMutex.Unlock()
            End If
            'Sleep
            Threading.Thread.Sleep(ThreadSleepTime)
        End While
    End Sub
    Private Function CheckPaket(ByVal Paket As String) As Boolean
        If Paket.Split("|")(1) = Net_Orders.MessageRecieved.ToString Then
            If WaitRecieving Then
                If CInt(Paket.Split("|")(0)) = ClientDataCounter - 1 Then
                    PaketRecevied = True
                End If
            End If
            Return False
        Else
            'Das ist ein Paket vom Server
            If CInt(Paket.Split("|")(0)) = ServerDataCounter Then
                'This Paket is new to us. We need to send a Mesage Recieved to the Client.
                SendRecieveToServer()
                Return True
            ElseIf CInt(Paket.Split("|")(0)) = ServerDataCounter - 1 Then
                ServerDataCounter -= 1
                'This Paket was recieved already. Resend Message recieved
                SendRecieveToServer()
                Return False
            Else
            End If
        End If
    End Function
    ''' <summary>
    ''' Wir senden ein Recieve zum Server
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub SendRecieveToServer()
        Dim P As New NetworkPaket()
        P.Write(ServerDataCounter.ToString + "|" + Net_Orders.MessageRecieved.ToString)
        Dim Data As Byte() = NetworkPaket.GenerateByteStream(P.ReadAll)
        Try
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            While Not networkStream.CanWrite
                Threading.Thread.Sleep(ThreadSleepTime)
            End While
            Dim DataSended As Boolean = False
            While Not DataSended And tcpClient.Client.Connected
                networkStream.Write(Data, 0, Data.Length) 'Sending Data
                DataSended = True
            End While
            ServerDataCounter += 1
        Catch e As Exception
            Konsole.Write("Sending Error: " + e.ToString)
        End Try

    End Sub
#End Region


    Public Function NetzConnected() As Boolean
        If tcpClient IsNot Nothing Then
            If tcpClient.Client IsNot Nothing Then
                Return tcpClient.Client.Connected
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function
    ''' <summary>
    ''' Checks if all Player are Ready to start the Game.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsGameReady() As Boolean
        Return Ready
    End Function
End Class

''' <summary>
''' The Class for the Server.
''' </summary>
''' <remarks></remarks>
Public Class ServerClassGame

    Dim ServerPaketLocker As New Mutex
    Dim WaitRecieving As Boolean = False
    Dim LastPaket As NetworkPaket
    ''' <summary>
    ''' Host for IPv4
    ''' </summary>
    ''' <remarks></remarks>
    Dim tcpListenerIP As TcpListener
    ''' <summary>
    ''' TcpClients of the Host.
    ''' </summary>
    ''' <remarks></remarks>
    Dim tcpClients As New List(Of Client)
    ''' <summary>
    ''' Connections that should be closed
    ''' </summary>
    ''' <remarks></remarks>
    Dim ClosingClients As New List(Of Integer)
    Private Class Client
        ''' <summary>
        '''Paket wurde vom Server empfangen
        ''' </summary>
        ''' <remarks></remarks>
        Public PaketRecevied As Boolean = False
        ''' <summary>
        ''' Paket Counter Client zum Server
        ''' </summary>
        ''' <remarks></remarks>
        Public ClientDataCounter As UInt64
        ''' <summary>
        ''' Paket Counter Server zum Client 
        ''' </summary>
        ''' <remarks></remarks>
        Public ServerDataCounter As UInt64
        Public tcpClient As TcpClient
        Public PlayerID As Integer = Integer.MinValue
        Public Ready As Boolean = False
        ''' <summary>
        ''' Backbuffer for our read in.
        ''' </summary>
        ''' <remarks></remarks>
        Public Data As New List(Of Byte)
        ''' <summary>
        ''' The Current Position of our Reader.
        ''' </summary>
        ''' <remarks></remarks>
        Public CurrentPos As Integer
        ''' <summary>
        ''' Did we send all Gameinfo to this Client?
        ''' </summary>
        ''' <remarks></remarks>
        Public NewlyCreated As Boolean = True
        Public Sub New(ByVal tcpClient As TcpClient, ByVal Clients As List(Of Client))
            Me.tcpClient = tcpClient
            Me.tcpClient.ReceiveBufferSize = NetworkPaket.MaxRecieveBuffer
            While PlayerIDExists(PlayerID, Clients)
                PlayerID += 1
            End While
        End Sub
        Public Function PlayerIDExists(ByVal ID As Integer, ByVal Clients As List(Of Client))
            For Each Client In Clients
                If Client.PlayerID = ID Then
                    Return True
                End If
            Next
            Return False
        End Function
    End Class
    ''' <summary>
    ''' Thread for the Listening
    ''' </summary>
    ''' <remarks></remarks>
    Dim ListenThread As Threading.Thread
    ''' <summary>
    ''' Closing connection
    ''' </summary>
    ''' <remarks></remarks>
    Dim CloseConnection As Boolean = False
    ''' <summary>
    ''' Is this Server ready to Start?
    ''' </summary>
    ''' <remarks></remarks>
    Dim Ready As Boolean = False
    ''' <summary>
    ''' Did we send the Ready Signal?
    ''' </summary>
    ''' <remarks></remarks>
    Dim ReadySended As Boolean = False
    ''' <summary>
    ''' Sending or Listening to Client  Pakets.
    ''' </summary>
    ''' <remarks></remarks>
    Dim SendListenMutex As New Mutex
    ''' <summary>
    ''' Are we connected?
    ''' </summary>
    ''' <remarks></remarks>
    Dim Connected As Boolean = False
    ''' <summary>
    ''' Pakets reciebied from Clients
    ''' </summary>
    ''' <remarks></remarks>
    Dim Pakets As New List(Of ServerPaket)


    Public Sub LaunchServer(ByVal Port As Integer, ByVal Local As Boolean)
        tcpListenerIP = New TcpListener(System.Net.IPAddress.Any, Port)
        tcpListenerIP.Start() 'Start Connection
        Connected = True
        ListenThread = New Threading.Thread(AddressOf RecieveData)
        ListenThread.Name = "Server Game Listening"
        ListenThread.Start()
    End Sub
    ''' <summary>
    ''' Closes this Client Session.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Close()
        CloseConnection = True
        Connected = False
        If tcpClients IsNot Nothing Then
            SendData(New NetworkPaket(Net_Orders.Close_Connection.ToString))
            For Each Client In tcpClients
                Client.tcpClient.Close()
            Next
            tcpClients.Clear()
        End If
        If tcpListenerIP IsNot Nothing Then
            tcpListenerIP.Stop()
        End If
        If ListenThread IsNot Nothing Then
            ListenThread.Abort()
        End If
    End Sub
#Region "Client to Server"
    ''' <summary>
    ''' Send Data to or Player
    ''' </summary>
    ''' <param name="Data"></param>
    ''' <remarks></remarks>
    Private Sub SendData(ByVal Data As NetworkPaket)
        SendData(Data, 0, True)
    End Sub
    ''' <summary>
    ''' Send Data to or Player
    ''' </summary>
    ''' <param name="Input"></param>
    ''' <remarks></remarks>
    Private Sub SendData(ByVal Input As NetworkPaket, ByVal PlayerID As Integer, ByVal ToAllPlayer As Boolean)
        SendData(Input, PlayerID, ToAllPlayer, False)
    End Sub
    ''' <summary>
    ''' Send Input to or Player
    ''' </summary>
    ''' <param name="Input"></param>
    ''' <remarks></remarks>
    Private Sub SendData(ByVal Input As NetworkPaket, ByVal PlayerID As Integer)
        SendData(Input, PlayerID, False, True)
    End Sub
    ''' <summary>
    ''' Send Data to or Player
    ''' </summary>
    ''' <param name="Input"></param>
    ''' <remarks></remarks>
    Private Sub SendData(ByVal Input As NetworkPaket, ByVal PlayerID As Integer, ByVal ToAllPlayer As Boolean, ByVal Only_To_Player As Boolean)
        If tcpClients IsNot Nothing Then
            If tcpClients.Count > 0 Then
                If NetzConnected() Then
                    For i = 0 To tcpClients.Count - 1
                        tcpClients(i).PaketRecevied = False
                    Next
                    LastPaket = Input
                    Dim LastRun As Long = Now.Ticks
                    If ToAllPlayer Then
                        SendListenMutex.Lock()
                        For i = 0 To tcpClients.Count - 1 'Send it to all other Clients
                            SendData(Input, tcpClients(i))
                        Next
                        WaitRecieving = True
                        SendListenMutex.Unlock()
                        'We don't need to send an answer or wait for it if it's a Message Recieved Message
                        While Not DataRecieved(LastRun, Only_To_Player, ToAllPlayer, PlayerID)
                            Threading.Thread.Sleep(ThreadSleepTime)
                        End While
                        WaitRecieving = False
                    ElseIf Only_To_Player Then
                        SendListenMutex.Lock()
                        For i = 0 To tcpClients.Count - 1 'Send it to all other Clients
                            If tcpClients(i).PlayerID = PlayerID Then
                                SendData(Input, tcpClients(i))
                                Exit For
                            End If
                        Next
                        WaitRecieving = True
                        SendListenMutex.Unlock()
                        'We don't need to send an answer or wait for it if it's a Message Recieved Message
                        While Not DataRecieved(LastRun, Only_To_Player, ToAllPlayer, PlayerID)
                            Threading.Thread.Sleep(ThreadSleepTime)
                        End While
                        WaitRecieving = False
                    Else
                        SendListenMutex.Lock()
                        For i = 0 To tcpClients.Count - 1 'Send it to all other Clients
                            If tcpClients(i).PlayerID <> PlayerID Then
                                SendData(Input, tcpClients(i))
                            End If
                        Next
                        WaitRecieving = True
                        SendListenMutex.Unlock()
                        'We don't need to send an answer or wait for it if it's a Message Recieved Message
                        While Not DataRecieved(LastRun, Only_To_Player, ToAllPlayer, PlayerID)
                            Threading.Thread.Sleep(ThreadSleepTime)
                        End While
                        WaitRecieving = False
                    End If
                End If
            End If
        End If
        LastPaket = Nothing
    End Sub
    Private Sub SendData(ByVal Input As NetworkPaket, ByRef TcpClient As Client)
        Dim P As New NetworkPaket()
        P.Write(TcpClient.ServerDataCounter.ToString + "|")
        P.Write(Input.ReadAll)
        Dim Data As Byte() = NetworkPaket.GenerateByteStream(P.ReadAll)
        Try
            Dim networkStream As NetworkStream = TcpClient.tcpClient.GetStream()
            While Not networkStream.CanWrite
                Threading.Thread.Sleep(ThreadSleepTime)
            End While
            Dim DataSended As Boolean = False
            While Not DataSended And TcpClient.tcpClient.Client.Connected
                networkStream.Write(Data, 0, Data.Length) 'Sending Data
                DataSended = True
            End While
            TcpClient.ServerDataCounter += 1
        Catch e As Exception
            Konsole.Write("Sending Error: " + e.ToString)
        End Try
    End Sub
    ''' <summary>
    ''' Did all Clients recieve our message?
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function DataRecieved(ByRef LastRun As Long, ByVal OnlyPlayerID As Boolean, ByVal ToAllPlayer As Boolean, ByVal PlayerID As Integer) As Boolean
        SendListenMutex.Lock()
        If OnlyPlayerID Then
            For I = 0 To tcpClients.Count - 1
                If tcpClients(I).PaketRecevied = False And tcpClients(I).PlayerID = PlayerID Then
                    If Now.Ticks - LastRun > Hauptmenue.ServerTimeOut Then

                        tcpClients(I).ServerDataCounter -= 1
                        SendData(LastPaket, tcpClients(I))

                        LastRun = Now.Ticks
                    End If
                    SendListenMutex.Unlock()
                    Return False
                End If
            Next
        ElseIf ToAllPlayer Then
            Dim Rerun As Boolean = False
            Dim Recieved As Boolean = True
            For I = 0 To tcpClients.Count - 1
                If tcpClients(I).PaketRecevied = False Then
                    If Now.Ticks - LastRun > Hauptmenue.ServerTimeOut Then
                        tcpClients(I).ServerDataCounter -= 1
                        SendData(LastPaket, tcpClients(I))
                        Rerun = True
                    End If
                    Recieved = False
                End If
            Next
            If Rerun Then
                LastRun = Now.Ticks
            End If
            If Not Recieved Then
                SendListenMutex.Unlock()
                Return False
            End If
        Else
            Dim Rerun As Boolean = False
            Dim Recieved As Boolean = True
            For I = 0 To tcpClients.Count - 1
                If tcpClients(I).PaketRecevied = False And PlayerID <> tcpClients(I).PlayerID Then
                    If Now.Ticks - LastRun > Hauptmenue.ServerTimeOut Then
                        tcpClients(I).ServerDataCounter -= 1
                        SendData(LastPaket, tcpClients(I))
                        Rerun = True
                    End If
                    Recieved = False
                End If
            Next
            If Rerun Then
                LastRun = Now.Ticks
            End If
            If Not Recieved Then
                SendListenMutex.Unlock()
                Return False
            End If
        End If
        SendListenMutex.Unlock()
        Return True
    End Function
#End Region


#Region "Server to Client"
    ''' <summary>
    ''' Recieve Data
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub RecieveData()
        Dim StartByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders.Start0000000000000000_.ToString)
        Dim EndByte As Byte() = Hauptmenue.Codierung.GetBytes(Net_Orders._End0000000000000000.ToString)
        While Not CloseConnection
            SendListenMutex.Lock()
            For I = 0 To ClosingClients.Count - 1
                CloseConnectionToClient(ClosingClients(I))
            Next
            ClosingClients.Clear()
            Dim I3 As Integer = 0
            While I3 < tcpClients.Count
                If Not tcpClients(I3).tcpClient.Client.Connected Then
                    CloseConnectionToClient(tcpClients(I3).PlayerID)
                Else
                    I3 += 1
                End If
            End While
            While tcpListenerIP.Pending  'Somebody wants to connect to us.
                tcpClients.Add(New Client(tcpListenerIP.AcceptTcpClient(), tcpClients))
            End While
            SendListenMutex.Unlock()
            If tcpClients IsNot Nothing Then
                For I = 0 To tcpClients.Count - 1
                    SendListenMutex.Lock()
                    Dim CurrentData As NetworkPaket = GameConnection.RecievePaket(tcpClients(I).tcpClient)
                    If CurrentData IsNot Nothing Then
                        Dim Data As String = CurrentData.ReadString
                        'Versions Kontrolle vor dem senden einfügen...
                        If CheckPaket(Data, tcpClients(I)) Then
                            If Data.Split("|")(1) <> Net_Orders.Player_Ready.ToString Then
                                ServerPaketLocker.Lock()
                                Pakets.Add(New ServerPaket(Data.Remove(0, Data.IndexOf("|")), tcpClients(I).PlayerID))
                                ServerPaketLocker.Unlock()
                            End If
                            'Use the Data
                            Select Case Data.Split("|")(1)
                                Case Net_Orders.Close_Connection.ToString
                                    ClosingClients.Add(tcpClients(I).PlayerID)
                                Case Net_Orders.Player_Ready.ToString
                                    tcpClients(I).Ready = True
                                Case Net_Orders.Player_Not_Ready.ToString
                                    ServerPaketLocker.Lock()
                                    Pakets.Add(New ServerPaket(Net_Orders.Player_Not_Ready.ToString, 0, True))
                                    ServerPaketLocker.Unlock()
                                    tcpClients(I).Ready = False
                                    ReadySended = False
                                Case Else
                                    Hauptmenue.NetzBefehlRecieved(CurrentData, tcpClients(I).PlayerID)
                            End Select
                        End If
                    End If
                    SendListenMutex.Unlock()
                Next
            End If

            'Sleep
            Threading.Thread.Sleep(ThreadSleepTime)
        End While
    End Sub


    Private Function CheckPaket(ByVal Paket As String, ByRef tcpClient As Client) As Boolean
        If Paket.Split("|")(1) = Net_Orders.MessageRecieved.ToString Then
            If WaitRecieving Then
                If CInt(Paket.Split("|")(0)) = tcpClient.ServerDataCounter - 1 Then
                    tcpClient.PaketRecevied = True
                End If
            End If
            Return False
        Else
            'Das ist ein Paket vom Server
            If CInt(Paket.Split("|")(0)) = tcpClient.ClientDataCounter Then
                'This Paket is new to us. We need to send a Mesage Recieved to the Client.
                SendRecieveToClient(tcpClient)
                Return True
            ElseIf CInt(Paket.Split("|")(0)) = tcpClient.ClientDataCounter - 1 Then
                tcpClient.ClientDataCounter -= 1
                'This Paket was recieved already. Resend Message recieved
                SendRecieveToClient(tcpClient)
                Return False
            Else
            End If
        End If
    End Function
    ''' <summary>
    ''' Wir senden ein Recieve zum Client
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub SendRecieveToClient(ByRef TcpClient As Client)
        Dim P As New NetworkPaket()
        P.Write(TcpClient.ClientDataCounter.ToString + "|" + Net_Orders.MessageRecieved.ToString)
        Dim Data As Byte() = NetworkPaket.GenerateByteStream(P.ReadAll)
        Try
            Dim networkStream As NetworkStream = TcpClient.tcpClient.GetStream()
            While Not networkStream.CanWrite
                Threading.Thread.Sleep(ThreadSleepTime)
            End While
            Dim DataSended As Boolean = False
            While Not DataSended And TcpClient.tcpClient.Connected
                networkStream.Write(Data, 0, Data.Length) 'Sending Data
                DataSended = True
            End While
            TcpClient.ClientDataCounter += 1
        Catch e As Exception
            Konsole.Write("Sending Error: " + e.ToString)
        End Try
    End Sub
#End Region
    Private Sub CloseConnectionToClient(ByVal ID As Integer)
        For I = 0 To tcpClients.Count - 1
            If tcpClients(I).PlayerID = ID Then
                tcpClients.RemoveAt(I)
                Exit For
            End If
        Next
    End Sub
    ''' <summary>
    ''' Checks if all Player are Ready to start the Game.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsGameReady() As Boolean
        If Ready Then
            For Each Client In tcpClients
                If Not Client.Ready Then
                    Return False
                End If
            Next
            Return True
        Else
            Return False
        End If
    End Function
    Public Sub AddServerPaket(ByVal Data As NetworkPaket)
        ServerPaketLocker.Lock()
        Pakets.Add(New ServerPaket(Data.ReadAll, 0, True, False))
        ServerPaketLocker.Unlock()
    End Sub
    Public Sub AddServerPaket(ByVal Data As NetworkPaket, ByVal PlayerId As Integer)
        ServerPaketLocker.Lock()
        Pakets.Add(New ServerPaket(Data.ReadAll, PlayerId, False, True))
        ServerPaketLocker.Unlock()
    End Sub
    ''' <summary>
    ''' We send all Network Pakets
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub SendPakets()
        ServerPaketLocker.Lock()
        Dim P As New List(Of ServerPaket)
        For i = 0 To Pakets.Count - 1
            P.Add(New ServerPaket(Pakets(i).Bytes, Pakets(i).PlayerID, Pakets(i).All_Player, Pakets(i).Only_To_Player))
        Next
        Pakets.Clear()
        ServerPaketLocker.Unlock()
        For i = 0 To P.Count - 1
            SendData(P(i), P(i).PlayerID, P(i).All_Player, P(i).Only_To_Player)
        Next
    End Sub
    Public Sub SendFirstUpdate()
        For i = 0 To tcpClients.Count - 1
            If tcpClients(i).NewlyCreated Then
                Hauptmenue.NetzDatenKartentransfer(tcpClients(i).PlayerID)
                Hauptmenue.NetzCustomDatentransfer(tcpClients(i).PlayerID)
                tcpClients(i).NewlyCreated = False
            End If
        Next
    End Sub
    Public Sub SendReady()
        If Not ReadySended Then
            Dim SendReady As Boolean = Ready
            If SendReady Then
                For Each Client In tcpClients
                    If Not Client.Ready Then
                        SendReady = False
                        Exit For
                    End If
                Next
                If SendReady Then
                    SendData(New NetworkPaket(Net_Orders.Player_Ready.ToString)) 'Send Ready Signal
                    ReadySended = True
                End If
            End If
        End If
    End Sub
    Public Sub IsReady(ByVal Ready As Net_Orders)
        Select Case Ready
            Case Net_Orders.Player_Ready
                Me.Ready = True
            Case Else
                Me.Ready = False
        End Select
    End Sub
    ''' <summary>
    ''' Are we connected
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function NetzConnected() As Boolean
        Return Connected
    End Function
    Public Function GetServerClients() As List(Of Integer)
        Dim Clients As New List(Of Integer)
        For i = 0 To tcpClients.Count - 1
            Clients.Add(tcpClients(i).PlayerID)
        Next
        Return Clients
    End Function
End Class
